import json
import logging
import string
from collections import OrderedDict
from datetime import datetime

import qiniu
import random
import re
from django.conf import settings
from django.contrib.auth import login
from django.core.paginator import EmptyPage, Paginator  # 分页器
from django.http import Http404
from django.shortcuts import render
from django.utils.http import urlencode
from django.views import View
from django.http import HttpResponse
from django.db.models import Count
from django.utils.decorators import method_decorator  # 类装饰器
from django.contrib.auth.decorators import permission_required, login_required  #
# 函数 权限.登录验证装饰器
from django.contrib.auth.mixins import PermissionRequiredMixin, LoginRequiredMixin  # 类 权限 登录验证装饰器
from django.contrib.auth.models import ContentType, Permission, Group
from django.core.mail import EmailMultiAlternatives
from django_redis import get_redis_connection

from admin import forms
from admin.forms import RePasswordForm
from user.forms import RegisterForm
from user.models import Users
from utils.fastdfs.fdfs import FDFS_Client
from utils.json_fun import JsonResponse
from utils.decorators.user_decorator import my_decorator, MydecoratorMixin
from news import models
from doc.models import Doc
from course.models import Course, Teacher, CourseCategory
from utils.json_fun import to_json_data
from utils.res_code import Code, error_map
from . import constants
from utils import paginator_script  # 传说中的分页算法
from utils.secrets import qiniu_secret_info

logger = logging.getLogger('django')


class UploadToken(PermissionRequiredMixin, View):
    """
    生成一个token反回前端,用于校验权限
    """
    permission_required = ('news.add_news',  # 添加新闻权限
                           'news.view_news',)
    raise_exception = True  # 如果无权限抛出 403 默认重定向到登录

    def handle_no_permission(self):
        return to_json_data(errno=Code.ROLEERR, errmsg='没有操作权限')

    def get(self, request):
        access_key = qiniu_secret_info.QI_NIU_ACCESS_KEY
        secret_key = qiniu_secret_info.QI_NIU_SECRET_KEY
        bucket_name = qiniu_secret_info.QI_NIU_BUCKET_NAME
        # 构建鉴权对象
        q = qiniu.Auth(access_key, secret_key)
        token = q.upload_token(bucket_name)

        return JsonResponse({"uptoken": token})


# @method_decorator(my_decorator,name='dispatch')#装饰类的实例方法  name='dispatch'分发参数
# @method_decorator(login_required(login_url="user:login"),name='dispatch') #登录验证的类装饰方法
# class  IndexView(MydecoratorMixin,View): #自定义mixin
class IndexView(LoginRequiredMixin, View):
    """
    creat admin index view
    url:/admin/
                    MydecoratorMixin是自定义的装饰器
                    LoginRequiredMixin是自带的装饰器
    """

    # login_url = "user:login" #还可以在settings里指定
    # @method_decorator(my_decorator)
    # @my_decorator
    def get(self, request):
        # print(IndexView.__mro__)
        return render(request, 'admin/index/index.html')


# @my_decorator#复习装饰器
# @login_required(login_url="user:login")
# 缺陷是只能装饰函数,如果装饰类还需自定义或者外面嵌套@method_decorator方法 @method_decorator(login_required(login_url="user:login"),name='dispatch')   自定义 Mixin 比较NB  但是推荐自带的 LoginRequiredMixin
# @login_required(login_url="user:login") #未登录的重定向地址
@permission_required('news.delete_news', raise_exception=True)  # 权限校验 反回403
def index_fn(request):
    return HttpResponse("老子天下第一")


# index_fn = my_decorator(index_fn)


# 1. 创建标签管理视图
# class TagManageView(View):

# 标签管理
class TagManageView(PermissionRequiredMixin, View):  # 加权限
    """
    creat tags manage view
    url:/admin/tags/
    """
    permission_required = ('news.add_tag',  # 添加新闻权限
                           'news.change_tag',
                           'news.delete_tag',
                           'news.view_tag',)
    raise_exception = True  # 如果无权限抛出 403 默认重定向到登录

    def handle_no_permission(self):
        if self.request.method.lower() != 'get':
            return to_json_data(errno=Code.ROLEERR, errmsg='没有操作权限')
        else:
            return super(TagManageView, self).handle_no_permission()

    # @property
    # def get_permission_required(self):#定义一个方法反回Tag所有权限
    #     content_type = ContentType.objects.get_for_model(models.Tag)
    #     permissions = Permission.objects.filter(content_type=content_type)#取出所有TAG所有权限
    #     print(permissions)
    #     return permissions
    #
    # permission_required = get_permission_required
    # raise_exception = True

    # 2.获取参数 tags/
    def get(self, request, tag_id=None):
        tags = models.Tag.objects.values('id', 'name').annotate(num_news=Count('news')).filter(
            is_delete=False).order_by('-num_news',
                                      'update_time')  # 取出Tag表中'id','name'字段,并分别以 news对应数量标注 出来 ,筛选,排序 values反回字典,only反回查询集
        # 3.反回渲染
        return render(request, 'admin/news/tags_manage.html', locals())

    # 2.删除方法 获取id tags/<int:tag_id>/
    def delete(self, request, tag_id):
        tag = models.Tag.objects.only('id').filter(is_delete=False, id=tag_id).first()
        if tag:
            # tag.delete()

            tag.is_delete = True
            tag.save(update_fields=['is_delete'])  # 优化措施,仅更新此字段

            return to_json_data(errmsg="标签删除成功")
        else:
            return to_json_data(errno=Code.PARAMERR, errmsg="需要删除的标签不存在")

    # 2.改名 news/<int:tag_id>/
    def put(self, request, tag_id):
        json_data = request.body
        if not json_data:
            return to_json_data(errno=Code.PARAMERR, errmsg=error_map[Code.PARAMERR])
        # 将json转化为dict
        dict_data = json.loads(json_data.decode('utf8'))
        tag_name = dict_data.get('name').strip()
        tag = models.Tag.objects.only('id').filter(id=tag_id).first()
        if tag:
            if tag_name:
                if not models.Tag.objects.only('id').filter(name=tag_name).exists():
                    tag.name = tag_name
                    tag.save(update_fields=['name'])
                    return to_json_data(errmsg="标签更新成功")
                else:
                    return to_json_data(errno=Code.DATAEXIST, errmsg="标签名已存在")
            else:
                return to_json_data(errno=Code.PARAMERR, errmsg="标签名为空")
        else:
            return to_json_data(errno=Code.PARAMERR, errmsg="需要更新的标签不存在")

    # 2.新增 post tags/
    def post(self, request):
        json_data = request.body
        if not json_data:
            return to_json_data(errno=Code.PARAMERR, errmsg=error_map[Code.PARAMERR])
        # 将json转化为dict
        dict_data = json.loads(json_data.decode('utf8'))
        tag_name = dict_data.get('name').strip()
        if tag_name:
            tag_tuple = models.Tag.objects.get_or_create(name=tag_name)
            tag_instance, tag_created_bolean = tag_tuple
            new_tag_dict = {
                "id": tag_instance.id,
                "name": tag_instance.name
            }
            return to_json_data(errmsg="标签创建成功", data=new_tag_dict) if tag_created_bolean else \
                to_json_data(errno=Code.DATAEXIST, errmsg="标签名已存在")
        else:
            return to_json_data(errno=Code.PARAMERR, errmsg="标签名为空")


# class Test(PermissionRequiredMixin,View):   #  没权限时反回json格式数据
#     permission_required = ('news.add_tag',  # 添加新闻权限
#                            'news.change_tag',
#                            'news.delete_tag',
#                            'news.view_tag',)
#     raise_exception = True  # 如果无权限抛出 403 默认重定向到登录
#     def handle_no_permission(self):#重写此方法
#         if self.raise_exception or self.request.user.is_authenticated:
#             raise PermissionDenied(self.get_permission_denied_message())
#         return redirect_to_login(self.request.get_full_path(), self.get_login_url(), self.get_redirect_field_name())
#
#     def get(self,request):
#         return to_json_data()

# 创建新闻管理视图
class NewsManageView(PermissionRequiredMixin, View):
    """
    url: /admin/news/
    """
    permission_required = ('news.add_news',  # 添加新闻权限
                           'news.change_news',
                           'news.delete_news',
                           'news.view_news',)
    raise_exception = True  # 如果无权限抛出 403 默认重定向到登录

    def handle_no_permission(self):
        if self.request.method.lower() != 'get':
            return to_json_data(errno=Code.ROLEERR, errmsg='没有操作权限')
        else:
            return super(NewsManageView, self).handle_no_permission()

    def get(self, request, news_id=None):
        # 文章标签展示
        tags = models.Tag.objects.only('id', 'name').filter(is_delete=False)

        if news_id:
            news = models.News.objects.filter(is_delete=False, id=news_id).first()
            return render(request, 'admin/news/news_pub.html', locals())

        # 1.后端准备待查数据
        newses = models.News.objects.only('id',
                                          'title',
                                          'author__username',
                                          'tag__name',
                                          'update_time'). \
            select_related('author', 'tag').filter(is_delete=False)
        # 2.通过过滤条件查询数据

        # 通过标签id过滤
        try:
            tag_id = int(request.GET.get('tag_id', 0))
        except Exception as e:
            logger.info("标签有误:\n{}".format(e))
            tag_id = 0
        newses = newses.filter(tag_id=tag_id) or newses  # 这里热门新闻是外键关联,以热度排序

        # 时间过滤
        try:
            start_time = request.GET.get('start_time', '')
            start_time = datetime.strptime(start_time, '%Y/%m/%d') if start_time else ""

            end_time = request.GET.get('end_time', '')
            end_time = datetime.strptime(end_time, '%Y/%m/%d') if end_time else ""
        except Exception as e:
            logger.info("用户输入时间有误:\n{}".format(e))
            start_time = end_time = ''

        if start_time and not end_time:
            newses = newses.filter(update_time__gte=start_time)
        elif not start_time and end_time:
            newses = newses.filter(update_time__lte=end_time)
        elif start_time and end_time:
            newses = newses.filter(update_time__range=(start_time, end_time))

        # 通过title过滤
        title = request.GET.get('title', '')
        if title:
            newses = newses.filter(title__icontains=title)  # i忽略大小写contains包含字段

        # 通过作者名过滤
        author_name = request.GET.get('author_name', '')
        if author_name:
            newses = newses.filter(author__username__icontains=author_name)

        # 4.分页操作
        # 获取页码
        try:
            page = int(request.GET.get('page', 1))
        except Exception as e:
            logger.info("页码有误:\n{}".format(e))
            page = 1
        paginator = Paginator(newses, constants.PER_PAGE_NEWS_COUNT)
        try:
            news_info = paginator.page(page)
        except EmptyPage:
            logger.info("访问超过最大页数")
            news_info = paginator.page(paginator.num_pages)
        # 传说很NB的分页算法
        paginator_data = paginator_script.get_paginator_data(paginator, news_info)

        # 5.模板渲染
        start_time = start_time.strftime('%Y/%m/%d') if start_time else ""
        end_time = end_time.strftime('%Y/%m/%d') if end_time else ""
        context = {
            'news_info': news_info,
            'tags': tags,
            'paginator': paginator,
            'start_time': start_time,
            "end_time": end_time,
            "title": title,
            "author_name": author_name,
            "tag_id": tag_id,
            "other_param": urlencode({
                "start_time": start_time,
                "end_time": end_time,
                "title": title,
                "author_name": author_name,
                "tag_id": tag_id,
            })
        }
        context.update(paginator_data)
        return render(request, 'admin/news/news_manage.html', context=context)

    # 2.删除方法 获取id news/<int:news_id>/
    def delete(self, request, news_id):
        news = models.News.objects.only('id').filter(is_delete=False, id=news_id).first()
        if news:
            news.is_delete = True
            news.save(update_fields=['is_delete'])  # 优化措施,仅更新此字段
            return to_json_data(errmsg="标签删除成功")
        else:
            return to_json_data(errno=Code.PARAMERR, errmsg="需要删除的新闻不存在")

    # 3.更新新闻
    def put(self, request, news_id):
        # 1. 获取前端参数
        news = models.News.objects.filter(is_delete=False, id=news_id).first()
        if not news:
            return to_json_data(errno=Code.NODATA, errmsg="需要更新的文章不存在")

        json_data = request.body
        if not json_data:
            return to_json_data(errno=Code.PARAMERR, errmsg=error_map[Code.PARAMERR])
        # 将json转化为dict
        dict_data = json.loads(json_data.decode('utf8'))

        # 2. 校验参数
        form = forms.NewsPubForm(data=dict_data)
        if form.is_valid():
            # 3. 保存到数据库
            """#bug
            news_instance = form.save(commit=False)  # commit=False先不提交
            # news_instance.author_id = request.user.id
            news_instance.author_id = request.user.id
            #bug
            #news_instance.id = news.id #Column 'create_time' cannot be null
            news_instance.save()  # commit=False先不提交
            """
            news.title = form.cleaned_data.get("title")
            news.digest = form.cleaned_data.get("digest")
            news.content = form.cleaned_data.get("content")
            news.tag_id = form.cleaned_data.get("tag").id
            news.image_url = form.cleaned_data.get("image_url")
            news.save()
            # 4. 反回前端json
            return to_json_data(errmsg='文章更新成功')
        else:
            # 定义一个错误信息列表
            err_msg_list = []
            for item in form.errors.get_json_data().values():
                err_msg_list.append(item[0].get('message'))
            err_msg_str = '/'.join(err_msg_list)  # 拼接错误信息为一个字符串
            # 4. 反回前端json
            return to_json_data(errno=Code.PARAMERR, errmsg=err_msg_str)


# 发布文章视图
class NewsPubView(PermissionRequiredMixin, View):
    """
    URL admin/news/pub
    """
    permission_required = ('news.add_news',  # 添加新闻权限
                           'news.change_news',
                           'news.delete_news',
                           'news.view_news',)
    raise_exception = True  # 如果无权限抛出 403 默认重定向到登录

    def handle_no_permission(self):
        if self.request.method.lower() != 'get':
            return to_json_data(errno=Code.ROLEERR, errmsg='没有操作权限')
        else:
            return super(NewsPubView, self).handle_no_permission()

    def get(self, request):
        tags = models.Tag.objects.only('id', 'name').filter(is_delete=False)
        return render(request, 'admin/news/news_pub.html', locals())

    def post(self, request):
        """
        构建文件存储服务器
        1. 文件同名,内容不同    uuid
        2. 文件名不同,内容同    MD5
        3. 存储大文件          压缩,文件碎片化
        4. 文件备份
        5. 下载速度            CDN多地放置服务器,分布式
        6. 文件转码
        使用阿里开源的 FastDFS 快速分布式文件系统具备以上特性
        """
        # 1. 获取前端参数
        json_data = request.body

        if not json_data:
            return to_json_data(errno=Code.PARAMERR, errmsg=error_map[Code.PARAMERR])
        # 将json转化为dict
        dict_data = json.loads(json_data.decode('utf8'))

        # 2. 校验参数
        form = forms.NewsPubForm(data=dict_data)
        if form.is_valid():
            # 3. 保存到数据库
            news_instance = form.save(commit=False)  # commit=False先不提交
            news_instance.author_id = request.user.id
            # news_instance.author_id = 1     # for test
            news_instance.save()
            # 4. 反回前端json
            return to_json_data(errmsg='文章创建成功')
        else:
            # 定义一个错误信息列表
            err_msg_list = []
            for item in form.errors.get_json_data().values():
                err_msg_list.append(item[0].get('message'))
            err_msg_str = '/'.join(err_msg_list)  # 拼接错误信息为一个字符串
            # 4. 反回前端json
            return to_json_data(errno=Code.PARAMERR, errmsg=err_msg_str)


# 图片存放视图,反回保存路径json格式
class NewsUploadImage(PermissionRequiredMixin, View):
    permission_required = ('news.add_news',)

    def handle_no_permission(self):
        return to_json_data(errno=Code.ROLEERR, errmsg="没有上传图片权限")

    def post(self, request):
        image_file = request.FILES.get('image_file')
        if not image_file:
            logger.info("从前端获取图片失败")
            return to_json_data(errno=Code.ROLEERR, errmsg="从前端获取图片失败")
        if image_file.content_type not in ('image/jpeg', 'image/png', 'image/gif'):
            return to_json_data(errno=Code.DATAERR, errmsg='不能上传非图片文件')
        try:
            image_ext_name = image_file.name.split('.')[-1]
        except Exception as e:
            logger.info('图片拓展名异常：\n{}'.format(e))
            image_ext_name = 'jpg'

        try:
            upload_res = FDFS_Client.upload_by_buffer(image_file.read(), file_ext_name=image_ext_name)
        except Exception as e:
            logger.error('图片上传出现异常：{}'.format(e))
            return to_json_data(errno=Code.UNKOWNERR, errmsg='图片上传异常')
        else:
            if upload_res.get('Status') != 'Upload successed.':
                logger.info('图片上传到FastDFS服务器失败')
                return to_json_data(Code.UNKOWNERR, errmsg='图片上传到服务器失败')
            else:
                image_name = upload_res.get('Remote file_id')
                image_url = settings.FASTDFS_SERVER_DOMAIN + image_name
                return to_json_data(data={'image_url': image_url}, errmsg='图片上传成功')


# 展示热门新闻
class HotNewsManageView(PermissionRequiredMixin, View):
    """
    hotnews/
    """
    permission_required = ('news.view_hotnews',)
    raise_exception = True

    def get(self, request):
        hot_news = models.HotNews.objects.select_related('news__tag'). \
                       only('news_id', 'news__title', 'news__tag__name', 'priority'). \
                       filter(is_delete=False).order_by('priority', '-news__clicks')[0:constants.SHOW_HOTNEWS_COUNT]

        return render(request, 'admin/news/news_hot.html', locals())


# 删除热门新闻 修改热度
class HotNewsEditView(PermissionRequiredMixin, View):
    """
    hotnews/<int:hotnews_id>/
    """
    permission_required = ('news.change_hotnews', 'news.delete_hotnews')
    raise_exception = True

    def handle_no_permission(self):
        if self.request.method.lower() != 'get':
            return to_json_data(errno=Code.ROLEERR, errmsg='没有操作权限')
        else:
            return super(HotNewsEditView, self).handle_no_permission()

    def delete(self, request, hotnews_id):
        hotnews = models.HotNews.objects.only('id').filter(id=hotnews_id).first()
        if hotnews:
            hotnews.is_delete = True
            hotnews.save(update_fields=['is_delete'])
            return to_json_data(errmsg="热门文章删除成功")
        else:
            return to_json_data(errno=Code.PARAMERR, errmsg="需要删除的热门文章不存在")

    def put(self, request, hotnews_id):
        json_data = request.body
        if not json_data:
            return to_json_data(errno=Code.PARAMERR, errmsg=error_map[Code.PARAMERR])
        # 将json转化为dict
        dict_data = json.loads(json_data.decode('utf8'))

        try:
            priority = int(dict_data.get('priority'))
            priority_list = [i for i, _ in models.HotNews.PRI_CHOICES]
            if priority not in priority_list:
                return to_json_data(errno=Code.PARAMERR, errmsg='热门文章的优先级设置错误')
        except Exception as e:
            logger.info('热门文章优先级异常：\n{}'.format(e))
            return to_json_data(errno=Code.PARAMERR, errmsg='热门文章的优先级设置错误')

        hotnews = models.HotNews.objects.only('id').filter(id=hotnews_id).first()
        if not hotnews:
            return to_json_data(errno=Code.PARAMERR, errmsg="需要更新的热门文章不存在")

        if hotnews.priority == priority:
            return to_json_data(errno=Code.PARAMERR, errmsg="热门文章的优先级未改变")

        hotnews.priority = priority
        hotnews.save(update_fields=['priority'])
        return to_json_data(errmsg="热门文章更新成功")


# 添加热门新闻
class HotNewsAddView(PermissionRequiredMixin, View):
    """
    route: /admin/hotnews/add/
    """
    permission_required = ('news.add_hotnews', 'news.view_hotnews')
    raise_exception = True

    def handle_no_permission(self):
        if self.request.method.lower() != 'get':
            return to_json_data(errno=Code.ROLEERR, errmsg='没有操作权限')
        else:
            return super(HotNewsAddView, self).handle_no_permission()

    def get(self, request):
        tags = models.Tag.objects.values('id', 'name').annotate(num_news=Count('news')). \
            filter(is_delete=False).order_by('-num_news', 'update_time')
        # 优先级列表
        # priority_list = {K: v for k, v in models.HotNews.PRI_CHOICES}
        priority_dict = OrderedDict(models.HotNews.PRI_CHOICES)  # OrderedDict将嵌套元组列表转化字典

        return render(request, 'admin/news/news_hot_add.html', locals())

    def post(self, request):
        json_data = request.body
        if not json_data:
            return to_json_data(errno=Code.PARAMERR, errmsg=error_map[Code.PARAMERR])
        # 将json转化为dict
        dict_data = json.loads(json_data.decode('utf8'))

        try:
            news_id = int(dict_data.get('news_id'))
        except Exception as e:
            logger.info('前端传过来的文章id参数异常：\n{}'.format(e))
            return to_json_data(errno=Code.PARAMERR, errmsg='参数错误')

        if not models.News.objects.filter(id=news_id).exists():
            return to_json_data(errno=Code.PARAMERR, errmsg='文章不存在')

        try:
            priority = int(dict_data.get('priority'))
            priority_list = [i for i, _ in models.HotNews.PRI_CHOICES]
            if priority not in priority_list:
                return to_json_data(errno=Code.PARAMERR, errmsg='热门文章的优先级设置错误')
        except Exception as e:
            logger.info('热门文章优先级异常：\n{}'.format(e))
            return to_json_data(errno=Code.PARAMERR, errmsg='热门文章的优先级设置错误')

        # 创建热门新闻
        hotnews_tuple = models.HotNews.objects.get_or_create(news_id=news_id)
        hotnews, is_created = hotnews_tuple
        hotnews.priority = priority  # 修改优先级
        hotnews.save(update_fields=['priority'])
        return to_json_data(errmsg="热门文章创建成功")


# 热门文章的二级选择
class NewsByTagIdView(PermissionRequiredMixin, View):
    """
    route: /admin/tags/<int:tag_id>/news/
    """
    permission_required = ('news.view_news', 'news.add_hotnews')

    # raise_exception = True

    def handle_no_permission(self):
        return to_json_data(errno=Code.ROLEERR, errmsg='没有操作权限')

    def get(self, request, tag_id):
        newses = models.News.objects.values('id', 'title').filter(is_delete=False, tag_id=tag_id)
        news_list = [i for i in newses]

        return to_json_data(data={
            'news': news_list
        })


# 轮播图管理
class BannerManageView(PermissionRequiredMixin, View):
    permission_required = ('news.add_banner',
                           'news.view_banner',
                           'news.change_banner',
                           'news.delete_banner')
    raise_exception = True

    # 获取轮播图管理页面 admin/banners/<int:banner_id>/
    def get(self, request, banner_id=None):
        """
        展示管理页面,如果banner_id存在反回post新增页面
        :param request:
        :return:get html priority news_title  post json
        """
        priority_dict = OrderedDict(models.Banner.PRI_CHOICES)  # OrderedDict将嵌套元组列表转化字典
        if not banner_id:  # banner_id 为默认参数时正常反回页面
            banners = models.Banner.objects.values('priority', 'image_url', 'id').filter(is_delete=False)
            return render(request, 'admin/news/news_banner.html', locals())

        # 参数不为默认值,说明是其新增时的参数,将banner_id当做tag_id
        tags = models.Tag.objects.values('id', 'name').filter(is_delete=False)
        return render(request, 'admin/news/news_banner_add.html', locals())

    # 轮播图更新接口 admin/banners/<int:banner_id>/
    def put(self, request, banner_id):
        """
        更新image_url,priority
        :param request: banner_id priority image_url
        :return: json
        """
        banner = models.Banner.objects.filter(id=banner_id, is_delete=False).first()
        if not banner:
            return to_json_data(errno=Code.NODATA, errmsg="轮播图不存在")
        # json转换dict
        json_data = request.body
        if not json_data:
            return to_json_data(errno=Code.PARAMERR, errmsg=error_map[Code.PARAMERR])
        # 将json转化为dict
        dict_data = json.loads(json_data.decode('utf8'))

        # 获取优先级priority参数
        try:
            priority = int(dict_data.get('priority'))
            priority_list = [i for i, _ in models.HotNews.PRI_CHOICES]
            if priority not in priority_list:
                return to_json_data(errno=Code.PARAMERR, errmsg='热门文章的优先级设置错误')
        except Exception as e:
            logger.info('热门文章优先级异常：\n{}'.format(e))
            return to_json_data(errno=Code.PARAMERR, errmsg='热门文章的优先级设置错误')

        # 获取image_url参数
        image_url = dict_data.get('image_url')
        if not image_url:
            return to_json_data(errno=Code.PARAMERR, errmsg='未上传图片')
        if banner.priority == priority and banner.image_url == image_url:
            return to_json_data(errno=Code.PARAMERR, errmsg='参数未改变')

        banner.priority = priority
        banner.image_url = image_url
        banner.save(update_fields=['priority', 'image_url'])
        return to_json_data(errmsg="轮播图更新成功")

    # 轮播图删除接口 admin/banners/<int:banner_id>/
    def delete(self, request, banner_id):
        """

        :param request:  banner_id
        :return:  json
        """
        banner = models.Banner.objects.filter(id=banner_id, is_delete=False).first()
        if not banner:
            return to_json_data(errno=Code.NODATA, errmsg="轮播图不存在")
        banner.is_delete = True
        banner.save(update_fields=['is_delete'])
        return to_json_data(errmsg="轮播图删除成功")

    # 轮播图新增接口 admin/banners/
    def post(self, request, banner_id=None):
        """

        :param request:  priority image_url  news_id
        :return:json
        """
        json_data = request.body
        if not json_data:
            return to_json_data(errno=Code.NODATA, errmsg="无数据")
        dict_data = json.loads(json_data.decode('utf8'))

        # priority校验合法性
        try:
            priority = int(dict_data.get('priority'))
            priority_list = [i for i, _ in models.Banner.PRI_CHOICES]
            if priority not in priority_list:
                return to_json_data(errno=Code.PARAMERR, errmsg='优先级设置错误')
        except Exception as e:
            return to_json_data(errno=Code.PARAMERR, errmsg='优先级设置错误')

        # image_url合法性
        image_url = dict_data.get('image_url')
        if not image_url:
            return to_json_data(errno=Code.PARAMERR, errmsg='轮播图片为空')

        # news_id 合法性
        try:
            news_id = int(dict_data.get('news_id'))
            if not models.News.objects.filter(id=news_id).exists():
                return to_json_data(errno=Code.PARAMERR, errmsg='文章不存在')
        except Exception as e:
            return to_json_data(errno=Code.PARAMERR, errmsg='文章不存在')

        banner, iscreate = models.Banner.objects.get_or_create(news_id=news_id)
        banner.news_id = news_id
        banner.priority = priority
        banner.image_url = image_url
        banner.save(update_fields=['priority', 'image_url', 'news_id'])
        return to_json_data(errmsg="轮播图创建成功")


# 文档管理
class DocsManageView(PermissionRequiredMixin, View):
    """
    route: /admin/docs/
    """
    permission_required = ('doc.view_doc', 'doc.add_doc', 'doc.change_doc', 'doc.delete_doc')
    raise_exception = True

    def handle_no_permission(self):
        if self.request.method.lower() != 'get':
            return to_json_data(errno=Code.ROLEERR, errmsg='没有操作权限')
        else:
            return super(DocsManageView, self).handle_no_permission()

    def get(self, request, doc_id=None):
        if not doc_id:
            docs = Doc.objects.only('title', 'create_time').filter(is_delete=False)
            return render(request, 'admin/doc/docs_manage.html', locals())
        doc = Doc.objects.filter(is_delete=False, id=doc_id).first()
        tags = Doc.objects.only('id', 'name').filter(is_delete=False)
        context = {
            'doc': doc
        }
        return render(request, 'admin/doc/docs_pub.html', locals())

    def delete(self, request, doc_id):
        doc = Doc.objects.filter(is_delete=False, id=doc_id).first()
        if doc:
            doc.is_delete = True
            doc.save(update_fields=['is_delete'])
            return to_json_data(errmsg="文档删除成功")
        else:
            return to_json_data(errno=Code.PARAMERR, errmsg="需要删除的文档不存在")

    def put(self, request, doc_id):
        doc = Doc.objects.filter(is_delete=False, id=doc_id).first()
        if not doc:
            return to_json_data(errno=Code.NODATA, errmsg='需要更新的文档不存在')

        json_data = request.body
        if not json_data:
            return to_json_data(errno=Code.PARAMERR, errmsg=error_map[Code.PARAMERR])
        # 将json转化为dict
        dict_data = json.loads(json_data.decode('utf8'))

        form = forms.DocsPubForm(data=dict_data)
        if form.is_valid():
            doc.title = form.cleaned_data.get('title')
            doc.desc = form.cleaned_data.get('desc')
            doc.file_url = form.cleaned_data.get('file_url')
            doc.image_url = form.cleaned_data.get('image_url')
            doc.save()
            return to_json_data(errmsg='文档更新成功')
        else:
            # 定义一个错误信息列表
            err_msg_list = []
            for item in form.errors.get_json_data().values():
                err_msg_list.append(item[0].get('message'))
            err_msg_str = '/'.join(err_msg_list)  # 拼接错误信息为一个字符串

            return to_json_data(errno=Code.PARAMERR, errmsg=err_msg_str)


# 文档发布视图
class DocsPubView(PermissionRequiredMixin, View):
    """
    route: /admin/news/pub/
    """
    permission_required = ('doc.add_doc', 'doc.view_doc')
    raise_exception = True

    def handle_no_permission(self):
        if self.request.method.lower() != 'get':
            return to_json_data(errno=Code.ROLEERR, errmsg='没有操作权限')
        else:
            return super(DocsPubView, self).handle_no_permission()

    def get(self, request):

        return render(request, 'admin/doc/docs_pub.html', locals())

    def post(self, request):
        json_data = request.body
        if not json_data:
            return to_json_data(errno=Code.PARAMERR, errmsg=error_map[Code.PARAMERR])
        # 将json转化为dict
        dict_data = json.loads(json_data.decode('utf8'))

        form = forms.DocsPubForm(data=dict_data)
        if form.is_valid():
            docs_instance = form.save(commit=False)
            docs_instance.author_id = request.user.id
            docs_instance.save()
            return to_json_data(errmsg='文档创建成功')
        else:
            # 定义一个错误信息列表
            err_msg_list = []
            for item in form.errors.get_json_data().values():
                err_msg_list.append(item[0].get('message'))
            err_msg_str = '/'.join(err_msg_list)  # 拼接错误信息为一个字符串

            return to_json_data(errno=Code.PARAMERR, errmsg=err_msg_str)


# 上传文章接口
class DocsUploadFile(PermissionRequiredMixin, View):
    """route: /admin/docs/files/
    """
    permission_required = ('doc.add_doc',)

    def handle_no_permission(self):
        return to_json_data(errno=Code.ROLEERR, errmsg='没有上传文件的权限')

    def post(self, request):
        text_file = request.FILES.get('text_file')
        if not text_file:
            logger.info('从前端获取文件失败')
            return to_json_data(errno=Code.NODATA, errmsg='从前端获取文件失败')

        if text_file.content_type not in ('application/msword', 'application/octet-stream', 'application/pdf',
                                          'application/zip', 'text/plain', 'application/x-rar'):
            return to_json_data(errno=Code.DATAERR, errmsg='不能上传非文本文件')

        try:
            text_ext_name = text_file.name.split('.')[-1]
        except Exception as e:
            logger.info('文件拓展名异常：{}'.format(e))
            text_ext_name = 'pdf'

        try:
            upload_res = FDFS_Client.upload_by_buffer(text_file.read(), file_ext_name=text_ext_name)
        except Exception as e:
            logger.error('文件上传出现异常：{}'.format(e))
            return to_json_data(errno=Code.UNKOWNERR, errmsg='文件上传异常')
        else:
            if upload_res.get('Status') != 'Upload successed.':
                logger.info('文件上传到FastDFS服务器失败')
                return to_json_data(Code.UNKOWNERR, errmsg='文件上传到服务器失败')
            else:
                text_name = upload_res.get('Remote file_id')
                text_url = settings.FASTDFS_SERVER_DOMAIN + text_name
                return to_json_data(data={'text_file': text_url}, errmsg='文件上传成功')


# 在线课堂管理
class CoursesManageView(PermissionRequiredMixin, View):
    """
    route: /admin/courses/
    """
    permission_required = ('course.add_course', 'course.view_course')
    raise_exception = True

    def handle_no_permission(self):
        if self.request.method.lower() != 'get':
            return to_json_data(errno=Code.ROLEERR, errmsg='没有操作权限')
        else:
            return super(CoursesManageView, self).handle_no_permission()

    def get(self, request):
        courses = Course.objects.select_related('category', 'teacher'). \
            only('title', 'category__name', 'teacher__name').filter(is_delete=False)
        return render(request, 'admin/course/courses_manage.html', locals())


# 在线课堂编辑
class CoursesEditView(PermissionRequiredMixin, View):
    """
    route: /admin/courses/<int:course_id>/
    """
    permission_required = ('course.change_course', 'course.delete_course')
    raise_exception = True

    def handle_no_permission(self):
        if self.request.method.lower() != 'get':
            return to_json_data(errno=Code.ROLEERR, errmsg='没有操作权限')
        else:
            return super(CoursesEditView, self).handle_no_permission()

    def get(self, request, course_id):
        """
        """
        course = Course.objects.filter(is_delete=False, id=course_id).first()
        if course:
            teachers = Teacher.objects.only('name').filter(is_delete=False)
            categories = CourseCategory.objects.only('name').filter(is_delete=False)
            return render(request, 'admin/course/courses_pub.html', locals())
        else:
            raise Http404('需要更新的课程不存在！')

    def delete(self, request, course_id):
        course = Course.objects.filter(is_delete=False, id=course_id).first()
        if course:
            course.is_delete = True
            course.save(update_fields=['is_delete'])
            return to_json_data(errmsg="课程删除成功")
        else:
            return to_json_data(errno=Code.PARAMERR, errmsg="需要删除的课程不存在")

    def put(self, request, course_id):
        course = Course.objects.filter(is_delete=False, id=course_id).first()
        if not course:
            return to_json_data(errno=Code.NODATA, errmsg='需要更新的课程不存在')

        json_data = request.body
        if not json_data:
            return to_json_data(errno=Code.PARAMERR, errmsg=error_map[Code.PARAMERR])
        # 将json转化为dict
        dict_data = json.loads(json_data.decode('utf8'))

        form = forms.CoursesPubForm(data=dict_data)
        if form.is_valid():
            for attr, value in form.cleaned_data.items():
                setattr(course, attr, value)

            course.save()
            return to_json_data(errmsg='课程更新成功')
        else:
            # 定义一个错误信息列表
            err_msg_list = []
            for item in form.errors.get_json_data().values():
                err_msg_list.append(item[0].get('message'))
            err_msg_str = '/'.join(err_msg_list)  # 拼接错误信息为一个字符串

            return to_json_data(errno=Code.PARAMERR, errmsg=err_msg_str)


# 在线课堂新增
class CoursesPubView(PermissionRequiredMixin, View):
    """
    route: /admin/courses/pub/
    """
    permission_required = ('course.add_course', 'course.view_course')
    raise_exception = True

    def handle_no_permission(self):
        if self.request.method.lower() != 'get':
            return to_json_data(errno=Code.ROLEERR, errmsg='没有操作权限')
        else:
            return super(CoursesPubView, self).handle_no_permission()

    def get(self, request):
        teachers = Teacher.objects.only('name').filter(is_delete=False)
        categories = CourseCategory.objects.only('name').filter(is_delete=False)
        return render(request, 'admin/course/courses_pub.html', locals())

    def post(self, request):
        json_data = request.body
        if not json_data:
            return to_json_data(errno=Code.PARAMERR, errmsg=error_map[Code.PARAMERR])
        dict_data = json.loads(json_data.decode('utf8'))

        form = forms.CoursesPubForm(data=dict_data)
        if form.is_valid():
            courses_instance = form.save()
            return to_json_data(errmsg='课程发布成功')
        else:
            # 定义一个错误信息列表
            err_msg_list = []
            for item in form.errors.get_json_data().values():
                err_msg_list.append(item[0].get('message'))
            err_msg_str = '/'.join(err_msg_list)  # 拼接错误信息为一个字符串

            return to_json_data(errno=Code.PARAMERR, errmsg=err_msg_str)


# 用户组
class GroupsManageView(PermissionRequiredMixin, View):
    """
    route: /admin/groups/
    """
    permission_required = ('auth.add_group', 'auth.view_group')
    raise_exception = True

    def handle_no_permission(self):
        if self.request.method.lower() != 'get':
            return to_json_data(errno=Code.ROLEERR, errmsg='没有操作权限')
        else:
            return super(GroupsManageView, self).handle_no_permission()

    def get(self, request):

        groups = Group.objects.values('id', 'name').annotate(num_users=Count('user')). \
            order_by('-num_users', 'id')
        return render(request, 'admin/user/groups_manage.html', locals())


# 用户组删除更新权限
class GroupsEditView(PermissionRequiredMixin, View):
    """
    route: /admin/groups/<int:group_id>/
    """
    permission_required = ('auth.change_group', 'auth.delete_group')
    raise_exception = True

    def handle_no_permission(self):
        if self.request.method.lower() != 'get':
            return to_json_data(errno=Code.ROLEERR, errmsg='没有操作权限')
        else:
            return super(GroupsEditView, self).handle_no_permission()

    def get(self, request, group_id):
        """
        """
        group = Group.objects.filter(id=group_id).first()
        if group:
            permissions = Permission.objects.only('id').all()
            return render(request, 'admin/user/groups_add.html', locals())
        else:
            raise Http404('需要更新的组不存在！')

    def delete(self, request, group_id):
        group = Group.objects.filter(id=group_id).first()
        if group:
            group.permissions.clear()  # 清空权限
            group.delete()
            return to_json_data(errmsg="用户组删除成功")
        else:
            return to_json_data(errno=Code.PARAMERR, errmsg="需要删除的用户组不存在")

    def put(self, request, group_id):
        group = Group.objects.filter(id=group_id).first()
        if not group:
            return to_json_data(errno=Code.NODATA, errmsg='需要更新的用户组不存在')

        json_data = request.body
        if not json_data:
            return to_json_data(errno=Code.PARAMERR, errmsg=error_map[Code.PARAMERR])
        # 将json转化为dict
        dict_data = json.loads(json_data.decode('utf8'))

        # 取出组名，进行判断
        group_name = dict_data.get('name', '').strip()
        if not group_name:
            return to_json_data(errno=Code.PARAMERR, errmsg='组名为空')

        if group_name != group.name and Group.objects.filter(name=group_name).exists():
            return to_json_data(errno=Code.DATAEXIST, errmsg='组名已存在')

        # 取出权限
        group_permissions = dict_data.get('group_permissions')
        if not group_permissions:
            return to_json_data(errno=Code.PARAMERR, errmsg='权限参数为空')

        try:
            permissions_set = set(int(i) for i in group_permissions)
        except Exception as e:
            logger.info('传的权限参数异常：\n{}'.format(e))
            return to_json_data(errno=Code.PARAMERR, errmsg='权限参数异常')

        all_permissions_set = set(i.id for i in Permission.objects.only('id'))
        if not permissions_set.issubset(all_permissions_set):
            return to_json_data(errno=Code.PARAMERR, errmsg='有不存在的权限参数')

        existed_permissions_set = set(i.id for i in group.permissions.all())  # bug
        if group_name == group.name and permissions_set == existed_permissions_set:
            return to_json_data(errno=Code.DATAEXIST, errmsg='用户组信息未修改')
        # 设置权限
        for perm_id in permissions_set:
            p = Permission.objects.get(id=perm_id)
            group.permissions.add(p)
        group.name = group_name
        group.save()
        return to_json_data(errmsg='组更新成功！')


# 用户组添加
class GroupsAddView(PermissionRequiredMixin, View):
    """
    route: /admin/groups/add/
    """
    permission_required = ('auth.add_group', 'auth.view_group')
    raise_exception = True

    def handle_no_permission(self):
        if self.request.method.lower() != 'get':
            return to_json_data(errno=Code.ROLEERR, errmsg='没有操作权限')
        else:
            return super(GroupsAddView, self).handle_no_permission()

    def get(self, request):
        permissions = Permission.objects.only('id').all()

        return render(request, 'admin/user/groups_add.html', locals())

    def post(self, request):
        json_data = request.body
        if not json_data:
            return to_json_data(errno=Code.PARAMERR, errmsg=error_map[Code.PARAMERR])
        dict_data = json.loads(json_data.decode('utf8'))

        # 取出组名，进行判断
        group_name = dict_data.get('name', '').strip()
        if not group_name:
            return to_json_data(errno=Code.PARAMERR, errmsg='组名为空')

        one_group, is_created = Group.objects.get_or_create(name=group_name)
        if not is_created:
            return to_json_data(errno=Code.DATAEXIST, errmsg='组名已存在')

        # 取出权限
        group_permissions = dict_data.get('group_permissions')
        if not group_permissions:
            return to_json_data(errno=Code.PARAMERR, errmsg='权限参数为空')

        try:
            permissions_set = set(int(i) for i in group_permissions)
        except Exception as e:
            logger.info('传的权限参数异常：\n{}'.format(e))
            return to_json_data(errno=Code.PARAMERR, errmsg='权限参数异常')

        all_permissions_set = set(i.id for i in Permission.objects.only('id'))
        if not permissions_set.issubset(all_permissions_set):
            return to_json_data(errno=Code.PARAMERR, errmsg='有不存在的权限参数')

        # 设置权限
        for perm_id in permissions_set:
            p = Permission.objects.get(id=perm_id)
            one_group.permissions.add(p)

        one_group.save()
        return to_json_data(errmsg='组创建成功！')


# 用户管理
class UsersManageView(PermissionRequiredMixin, View):
    """
    route: /admin/users/
    """
    permission_required = ('users.add_users', 'users.view_users')
    raise_exception = True

    def handle_no_permission(self):
        if self.request.method.lower() != 'get':
            return to_json_data(errno=Code.ROLEERR, errmsg='没有操作权限')
        else:
            return super(UsersManageView, self).handle_no_permission()

    def get(self, request):
        users = Users.objects.only('username', 'is_staff', 'is_superuser').filter(is_active=True)
        return render(request, 'admin/user/users_manage.html', locals())


# 用户权限修改
class UsersEditView(PermissionRequiredMixin, View):
    """
    route: /admin/users/<int:user_id>/
    """
    permission_required = ('users.change_users', 'users.delete_users')
    raise_exception = True

    def handle_no_permission(self):
        if self.request.method.lower() != 'get':
            return to_json_data(errno=Code.ROLEERR, errmsg='没有操作权限')
        else:
            return super(UsersEditView, self).handle_no_permission()

    def get(self, request, user_id):
        user_instance = Users.objects.filter(id=user_id).first()
        if user_instance:
            groups = Group.objects.only('name').all()
            return render(request, 'admin/user/users_edit.html', locals())
        else:
            raise Http404('需要更新的用户不存在！')

    def delete(self, request, user_id):
        user_instance = Users.objects.filter(id=user_id).first()
        if user_instance:
            user_instance.groups.clear()  # 清除用户组
            user_instance.user_permissions.clear()  # 清除用户权限
            user_instance.is_active = False  # 设置为不激活状态
            user_instance.save()
            return to_json_data(errmsg="用户删除成功")
        else:
            return to_json_data(errno=Code.PARAMERR, errmsg="需要删除的用户不存在")

    def put(self, request, user_id):
        user_instance = Users.objects.filter(id=user_id).first()
        if not user_instance:
            return to_json_data(errno=Code.NODATA, errmsg='需要更新的用户不存在')

        json_data = request.body
        if not json_data:
            return to_json_data(errno=Code.PARAMERR, errmsg=error_map[Code.PARAMERR])
        # 将json转化为dict
        dict_data = json.loads(json_data.decode('utf8'))

        # 取出参数，进行判断
        try:
            groups = dict_data.get('groups')  # 取出用户组列表

            is_staff = int(dict_data.get('is_staff'))
            is_superuser = int(dict_data.get('is_superuser'))
            is_active = int(dict_data.get('is_active'))
            params = [is_staff, is_superuser, is_active]
            if not all([p in (0, 1) for p in params]):
                return to_json_data(errno=Code.PARAMERR, errmsg='参数错误')
        except Exception as e:
            logger.info('从前端获取参数出现异常：\n{}'.format(e))
            return to_json_data(errno=Code.PARAMERR, errmsg='参数错误')

        try:
            groups_set = set(int(i) for i in groups) if groups else set()
        except Exception as e:
            logger.info('传的用户组参数异常：\n{}'.format(e))
            return to_json_data(errno=Code.PARAMERR, errmsg='用户组参数异常')

        all_groups_set = set(i.id for i in Group.objects.only('id'))
        if not groups_set.issubset(all_groups_set):
            return to_json_data(errno=Code.PARAMERR, errmsg='有不存在的用户组参数')

        gs = Group.objects.filter(id__in=groups_set)
        # 先清除组
        user_instance.groups.clear()
        user_instance.groups.set(gs)

        user_instance.is_staff = bool(is_staff)
        user_instance.is_superuser = bool(is_superuser)
        user_instance.is_active = bool(is_active)
        user_instance.save()
        return to_json_data(errmsg='用户信息更新成功！')


# 发送邮件--生成验证码--生成验证连接
class Send_email(View):
    def make_sms_num(self, username):  # 清空并生成验证码
        sms_num = ''.join([random.choice(string.digits) for _ in range(constants.SMS_CODE_NUMS)])
        redis_con = get_redis_connection(alias='verify_codes')  # redis连接器
        sms_text = "sms_{}".format(username)  # 邮箱验证码文本
        sms_text_fmt = sms_text.encode('utf-8')  # 保存文本邮箱验证码文本

        try:
            redis_con.setex(sms_text_fmt, constants.SMS_CODE_REDIS_EXPIRES, sms_num)  # 邮箱验证码有效期，单位分钟
        except Exception as e:
            logger.debug('redis执行一次,{}'.format(e))
            return to_json_data(errno=Code.UNKOWNERR, errmsg=error_map[Code.UNKOWNERR])
        return sms_text, sms_num

    def make_repassword_url(self, sms_text_fmt, sms_num):
        url = "192.168.6.136:8000" + "/admin/email/" + sms_text_fmt + "/" + sms_num + "/"
        return url

    @staticmethod
    def send_email(username, useremail, html_content):  # 发送邮件逻辑
        # if not username and not useremail:
        #     return to_json_data(errno=Code.PARAMERR, errmsg="用户信息不足")
        subject, form_email, to = '找回密码', '15607506008@163.com', useremail  # 主题,发件箱,收件箱
        text_content = 'This is an important message'
        try:
            msg = EmailMultiAlternatives(subject, text_content, form_email, [to])
            msg.attach_alternative(html_content, 'text/html')
            msg.send()
            return to_json_data(errno=Code.PARAMERR, errmsg="已发送邮件")
        except Exception as e:
            logger.info('邮件发送失败:\n{}'.format(e))
            return to_json_data(errno=Code.PARAMERR, errmsg="发送邮件发生未知错误")


# 重置密码
class RepasswordView(Send_email):
    def get(self, request, sms_text, sms_num):
        if sms_text and sms_num:
            # 2 获取图片验证码
            try:
                con_redis = get_redis_connection(alias='verify_codes')  # redis连接器
            except Exception as e:
                return HttpResponse('未知错误')
            try:
                sms_text_fmt, sms_num = sms_text.encode('utf-8'), sms_num.encode('utf-8')
            except Exception as  e:
                return HttpResponse('别乱点')

            real_sms_num = con_redis.get(sms_text_fmt)  # 获取redis中key值
            if sms_num != real_sms_num:
                return HttpResponse('验证码不对哦')
            return HttpResponse('是你')
        else:
            return HttpResponse('别闹')

    def put(self, request, sms_text, sms_num):
        json_data = request.body
        if not json_data:
            return to_json_data(errno=Code.PARAMERR, errmsg=error_map[Code.PARAMERR])
        # 将json转化为dict
        dict_data = json.loads(json_data.decode('utf8'))
        # 身份验证
        body_username = dict_data.get('username', '')
        url_username = re.match('sms_(.*)', sms_text).group(1)
        if not body_username or not url_username or body_username != url_username:
            return to_json_data(errno=Code.PARAMERR, errmsg="非法修改")

        try:
            con_redis = get_redis_connection(alias='verify_codes')  # redis连接器
        except Exception as e:
            return HttpResponse('未知错误')
        try:
            sms_text_fmt, sms_num = sms_text.encode('utf-8'), sms_num.encode('utf-8')
        except Exception as  e:
            return HttpResponse('别乱点')

        real_sms_num = con_redis.get(sms_text_fmt)  # 获取redis中key值
        if not sms_num or sms_num != real_sms_num:
            return HttpResponse('验证码不对哦')

        # 4.form表单校验参数
        form = RePasswordForm(data=dict_data)  # 传入表单数据
        # 5.将用户信息保存到数据库
        if form.is_valid():  # 如果校验成功
            username = form.cleaned_data.get('username')
            password = form.cleaned_data.get('password')
            user = Users.objects.get(username=username)
            user.set_password(password)
            user.save(update_fields=['password'])
            login(request, user)  # 将 用户登录信息 存放到session
            try:
                con_redis = get_redis_connection(alias='verify_codes')  # redis连接器
                sms_text_fmt, sms_num = sms_text.encode('utf-8'), sms_num.encode('utf-8')
                con_redis.delete(sms_text_fmt)  # 获取图片验证码后第一时间删除
                return to_json_data(errmsg='密码修改成功!')
            except Exception as  e:
                return HttpResponse('未知错误:\n{}'.format(e))
        else:  # 校验失败
            # 序列化错误信息
            err_msg_list = []
            for item in form.errors.get_json_data().values():
                err_msg_list.append(item[0].get('message'))
            err_msg_str = '/'.join(err_msg_list)  # 拼接错误信息为一个字符串
            # 6.反回前端
            return to_json_data(errno=Code.PARAMERR, errmsg=err_msg_str)

    def post(self, request):
        json_data = request.body
        if not json_data:
            return to_json_data(errno=Code.PARAMERR, errmsg=error_map[Code.PARAMERR])
        dict_data = json.loads(json_data.decode('utf8'))

        username = dict_data.get('username', '')
        useremail = dict_data.get('email', '')
        sms_text, sms_num = self.make_sms_num(username)  # 生成验证码
        re_url = self.make_repassword_url(sms_text, sms_num)
        html_content = u'''欢迎{}使用找回密码功能。
        验证码为：<h3>{}</h3>
        (该验证码在24小时内有效)或者使用连接验证:<a href="{}">{}</a>
        如果上面不是链接形式，请将地址复制到您的浏览器(例如IE)的地址栏再访问'''.format(username, sms_num, re_url, re_url)
        if Users.objects.filter(username=username, email=useremail).exists():
            rest = self.send_email(username=username, useremail=useremail, html_content=html_content)  # 发送验证码
            return rest
        else:
            return to_json_data(errno=Code.PARAMERR, errmsg="用户不存在")
